﻿using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace sharpCmd.Windows.Forms
{
    /// <summary>
    /// Column sorter used in listboxes
    /// </summary>
    internal class ColumnSorter : IComparer
    {
        private CaseInsensitiveComparer comparer;

        public ColumnSorter()
        {
            ColumnToSort = 0;
            SortOrder = SortOrder.Ascending;
            comparer = new CaseInsensitiveComparer();
        }

        public int ColumnToSort { get; set; }
        public SortOrder SortOrder { get; set; }

        /// <summary>
        /// Compares two objects
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public int Compare(object x, object y)
        {
            //we know arguments are listViewItemsEx
            /* in sorting, directory "always wins"
             * that means it is always sorted first
             * Directories are also always sorted by name ascending
             * Size and date are by default descending
             */
            const int ITEMX = -1;
            const int ITEMY = 1;
            ListViewItemEx itemX = (ListViewItemEx)x;
            ListViewItemEx itemY = (ListViewItemEx)y;
            if (itemX.Info.AlwaysOnTop)
                return ITEMX;
            else if (itemY.Info.AlwaysOnTop)
                return ITEMY;
            else if (itemX.Info.Type == Classes.FSObjectType.Directory && itemY.Info.Type == Classes.FSObjectType.File)
                return ITEMX; //itemX first
            else if (itemX.Info.Type == Classes.FSObjectType.File && itemY.Info.Type == Classes.FSObjectType.Directory)
                return ITEMY; //itemY first
            else if (itemX.Info.Type == Classes.FSObjectType.Directory && itemY.Info.Type == Classes.FSObjectType.Directory)
                return StrCmpLogicalW(itemX.Info.Name, itemY.Info.Name); 
            else //file,file
            {
                int result;
                switch (ColumnToSort)
                {
                    case 0: //name
                    case 1: //ext
                        result = StrCmpLogicalW(itemX.SubItems[ColumnToSort].Text, itemY.SubItems[ColumnToSort].Text);
                        break;
                    case 2: //size
                        result = (itemX.Info.Size > itemY.Info.Size) ? ITEMX : ITEMY;
                        break;
                    case 3: //date
                    default:
                        result = DateTime.Compare(itemX.Info.LastWriteTime, itemY.Info.LastWriteTime);
                        break;
                }
                switch (SortOrder)
                {
                    case SortOrder.Ascending:
                        return result;
                    case SortOrder.Descending:
                        return -result; //negative result, to be descending
                    default:
                        return 0; //no sorting order
                }
            }
        }

        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
        private static extern int StrCmpLogicalW(string psz1, string psz2);
    }
}